﻿
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;



namespace DKE_Kinect.Entwicklung.Grafik
{
    /// <summary>
    /// Klasse für die Kamera im 3D Raum
    /// </summary>
    public class Camera3D
    {
        private Vector3 pPosition;
        private Vector3 pLookAt;
        private Matrix pViewMatrix;
        private Matrix pProjectionMatrix;
        private float pAspectRatio;
        private BoundingFrustum pFrustum;

        /// <summary>
        /// Gets the frustum.
        /// </summary>
        public BoundingFrustum Frustum
        {
            get { return this.pFrustum; }

        }
        /// <summary>
        /// Initializes a new instance of the <see cref="Camera3D"/> class.
        /// </summary>
        /// <param name="viewport">The viewport.</param>
        public Camera3D(Viewport viewport)
        {
 
            this.pAspectRatio = ((float)viewport.Width) / ((float)viewport.Height);
            this.pProjectionMatrix = Matrix.CreatePerspectiveFieldOfView( MathHelper.PiOver4,
                                        this.pAspectRatio,
                                        10,
                                        10000.0f);
            pPosition = Vector3.Zero;
            pLookAt = Vector3.Zero;
            update();
        }

        /// <summary>
        /// Gets or sets the position.
        /// </summary>
        /// <value>
        /// The position.
        /// </value>
        public Vector3 Position
        {
            get { return this.pPosition; }
            set { this.pPosition = value; update(); }
        }
        /// <summary>
        /// Gets or sets the look at.
        /// </summary>
        /// <value>
        /// The look at.
        /// </value>
        public Vector3 LookAt
        {
            get { return this.pLookAt; }
            set { this.pLookAt = value; }
        }
        /// <summary>
        /// Gets the view matrix.
        /// </summary>
        public Matrix ViewMatrix
        {
            get { return this.pViewMatrix; }
        }
        /// <summary>
        /// Gets the projection matrix.
        /// </summary>
        public Matrix ProjectionMatrix
        {
            get { return this.pProjectionMatrix; }
        }
        /// <summary>
        /// Updates this instance.
        /// </summary>
        private void update()
        {
         
            this.pViewMatrix =
                Matrix.CreateLookAt(this.pPosition, this.pLookAt, Vector3.Up);
            pFrustum = new BoundingFrustum(Matrix.Multiply(ViewMatrix,pProjectionMatrix));
        }

        /// <summary>
        /// Moves Camera orbital.
        /// </summary>
        /// <param name="_move">Vector to move.</param>
        public void MoveOrbital(Vector3 _move)
        {
            pPosition = Vector3.Add(pPosition, _move);
            update();
        }

        /// <summary>
        /// Moves the look at target.
        /// </summary>
        /// <param name="_moveTarget">The move vector for the target.</param>
        public void MoveLookAtTarget(Vector3 _moveTarget)
        {
            pLookAt = Vector3.Add(pLookAt, _moveTarget);
            update();
        }

        /// <summary>
        /// Moves the complete camera.
        /// </summary>
        /// <param name="_move">The move to make.</param>
        public void MoveComplete(Vector3 _move)
        {
            pPosition = Vector3.Add(pPosition,_move);
            pLookAt = Vector3.Add(pLookAt,_move);
            update();
        }

        /// <summary>
        /// Sets the look at target.
        /// </summary>
        /// <param name="_newLookAt">The _new look at.</param>
        public void SetLookAt(Vector3 _newLookAt)
        {
            pLookAt = _newLookAt;
            update();
        }

        /// <summary>
        /// Sets the pos.
        /// </summary>
        /// <param name="_newPos">The _new pos.</param>
        public void SetPos(Vector3 _newPos)
        {
            pPosition = _newPos;
            update();
        }

        /// <summary>
        /// Applies a vector to the camera plane.
        /// </summary>
        /// <param name="vector2apply">The vector2apply.</param>
        /// <returns></returns>
        public Vector3 applyToPlane(Vector3 vector2apply)
        {
            Vector3 result = new Vector3();
            result.X = Vector3.Dot(vector2apply, pViewMatrix.Left);
            result.Y = Vector3.Dot(vector2apply, pViewMatrix.Up);
            result.Z = Vector3.Dot(vector2apply, pViewMatrix.Forward);
            return result; 
        }
    }
}
